package com.ev.apis.controller.mes;

import com.alibaba.fastjson.util.TypeUtils;
import com.ev.apis.model.DsResultResponse;
import com.ev.asl.constant.AslConstant;
import com.ev.asl.domain.MoldingProductionInstructionDO;
import com.ev.asl.service.AssemblyInstructionService;
import com.ev.asl.service.MoldingProductionInstructionService;
import com.ev.common.enums.AuditStatusDict;
import com.ev.custom.domain.MaterielDO;
import com.ev.custom.service.MaterielService;
import com.ev.framework.annotation.EvApiByToken;
import com.ev.framework.config.ConstantForMES;
import com.ev.framework.il8n.MessageSourceHandler;
import com.ev.framework.utils.PageUtils;
import com.ev.framework.utils.R;
import com.ev.framework.utils.StringUtils;
import com.ev.mes.domain.*;
import com.ev.mes.service.*;
import com.ev.report.vo.PieceRateVO;
import com.ev.scm.domain.SalescontractDO;
import com.ev.scm.service.SalescontractService;
import com.ev.scm.service.StockInItemService;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.util.MapUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 生产计划管理
 *
 * @author gumingjie
 * @email gumingjie.qi@gmail.com
 * @date 2019-11-21 09:51:41
 */

@Api(value = "/", tags = "生产计划API")
@RestController
public class ProductionPlanApiController {

	@Autowired
	private BomService bomService;
	@Autowired
	private BomDetailService bomDetailService;
	@Autowired
	private MaterielService materielService;
	@Autowired
	private ProductionPlanService productionPlanService;
	@Autowired
	private StockInItemService stockInItemService;
	@Autowired
	private ProductionPlanAlterationService productionPlanAlterationService;
	@Autowired
	private MessageSourceHandler messageSourceHandler;
	@Autowired
	private WorkingProcedurePlanService workingProcedurePlanService;
	@Autowired
	private MaterialInspectionService materialInspectionService;
	@Autowired
	private SalescontractService salescontractService;

	@Autowired
	private MoldingProductionInstructionService  mpiService;
	@Autowired
	private AssemblyInstructionService aiService;

	/**
	 *
	 * 获取生产计划列表
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@EvApiByToken(value = "/apis/productionPlan/list", method = RequestMethod.POST, apiTitle = "生产计划列表")
	@ApiOperation("获取生产计划列表")
	public R list(
			@ApiParam(value = "当前第几页", required = true) @RequestParam(value = "pageno", defaultValue = "1") int pageno,
			@ApiParam(value = "一页多少条", required = true) @RequestParam(value = "pagesize", defaultValue = "20") int pagesize,
			@ApiParam(value = "客户ID") @RequestParam(value = "clientId", defaultValue = "", required = false) Long clientId,
			@ApiParam(value = "客户名称") @RequestParam(value = "clientName", defaultValue = "", required = false) String clientName,
			@ApiParam(value = "任务单号") @RequestParam(value = "planNo", defaultValue = "", required = false) String planNo,
			@ApiParam(value = "产品名称") @RequestParam(value = "proName", defaultValue = "", required = false) String proName,
			@ApiParam(value = "部门ID") @RequestParam(value = "deptId", defaultValue = "", required = false) Long deptId,
			@ApiParam(value = "状态ID") @RequestParam(value = "status", defaultValue = "", required = false) Integer status,
			@ApiParam(value = "开始时间") @RequestParam(value = "startTime", defaultValue = "", required = false) String startTime,
			@ApiParam(value = "结束时间") @RequestParam(value = "endTime", defaultValue = "", required = false) String endTime,
			@ApiParam(value = "标识(dialog下达状态)") @RequestParam(value = "mark", defaultValue = "", required = false) String mark,
			@ApiParam(value = "需排序字段") @RequestParam(value = "sort",defaultValue = "",required = false)  String sort,
			@ApiParam(value = "升（asc）降(desc)序") @RequestParam(value = "order",defaultValue = "",required = false)  String order,
			@ApiParam(value = "dialog类型，生产入库引用:1") @RequestParam(value = "dialogType",defaultValue = "0",required = false)  Integer dialogType,
			@ApiParam(value = "成型、组装") @RequestParam(value = "newType",defaultValue = "",required = false)  Integer newType
//			@ApiParam(value = "生产计划名称", required = false) @RequestParam(value = "productionPlanName", defaultValue = "", required = false) String productionPlanName,
//			@ApiParam(value = "物料代码", required = false) @RequestParam(value = "serialNo", defaultValue = "", required = false) String serialNo,
	) {
		boolean isDiaLog = StringUtils.isNoneEmpty(mark)&&"dialog".equals(mark);
		// 查询列表数据
		Map<String, Object> params = Maps.newHashMap();

		if (Objects.nonNull(newType)){
			List<Long> planIds = new ArrayList<>();
			if (AslConstant.ONE.equals(newType)){
				planIds = mpiService.getPlanIds();
			}
			if (AslConstant.TWO.equals(newType)){
				planIds = aiService.getPlanIds();
			}

			params.put("ids",planIds);
		}

		// 自定义排序规则
		if (StringUtils.isNoneEmpty(sort)) {
			params.put("offset", 0);
			params.put("limit", 1);
			List<Map<String, Object>> maps = this.productionPlanService.listForMap(params);
			if (maps.size() > 0 && maps.get(0).containsKey(sort)) {
				params.put("sort", sort);
				params.put("order", StringUtils.isOrder(order));
			}
		}
		params.put("clientId", clientId);
		params.put("clientName", clientName);
		params.put("proName", proName);
		params.put("newType", newType);
		params.put("deptId", deptId);
		params.put("status", status);
		params.put("startTime", startTime);
		params.put("endTime", endTime);
		params.put("planNo",planNo);
//		params.put("serialNo", serialNo);
		boolean isDialogType =  dialogType!= 0;
		// 若是dialog 引用暂时不分页
		if (!isDialogType) {
			params.put("offset", (pageno - 1) * pagesize);
			params.put("limit", pagesize);
		}
		List<Map<String, Object>> data;
		// 产品检验单关联生产计划选单时，生产计划必须是设定必须检验且状态是下达状态的单据
		if (isDiaLog){
			params.put("status",ConstantForMES.ISSUED);
//			params.put("auditSign", AuditStatusDict.OK_AUDIT.getId());
//            params.put("isCheck",1);
			data = productionPlanService.listDialogMap(params);
		}else{
			data = productionPlanService.listForMap(params);
		}
//		BigDecimal aGroupNumberTotal = BigDecimal.ZERO;
//		BigDecimal bGroupNumberTotal = BigDecimal.ZERO;
//		BigDecimal cGroupNumberTotal = BigDecimal.ZERO;
//		for (Map<String, Object> map : data) {
//			aGroupNumberTotal = aGroupNumberTotal
//					.add(new BigDecimal(String.valueOf(map.get("aGroupNumber"))))
//					.setScale(2, BigDecimal.ROUND_HALF_UP);
//			bGroupNumberTotal = bGroupNumberTotal
//					.add(new BigDecimal(String.valueOf(map.get("bGroupNumber"))))
//					.setScale(2, BigDecimal.ROUND_HALF_UP);
//			cGroupNumberTotal = cGroupNumberTotal
//					.add(new BigDecimal(String.valueOf(map.get("cGroupNumber"))))
//					.setScale(2, BigDecimal.ROUND_HALF_UP);
//		}
		Map<String, Object> results = Maps.newHashMapWithExpectedSize(1);
		Map<String, Object> count = productionPlanService.countForMap(params);
		results.put("count", count);
		int total = count.containsKey("total") ? Integer.parseInt(count.get("total").toString()) : 0;
		if (data.size() > 0) {
			List<String> sourceCodes = data.stream().filter(e -> e.containsKey("sourceNo")).map(e -> e.get("sourceNo").toString()).collect(Collectors.toList());
			if (sourceCodes.size() > 0) {
				Map<String,Object> param = Maps.newHashMap();
				param.put("codes",sourceCodes);
				List<SalescontractDO> list = salescontractService.list(param);
				Map<String, Long> codeToId = list.stream().collect(Collectors.toMap(SalescontractDO::getContractCode, SalescontractDO::getId));
				data.forEach(e->{
					String sourceCode = e.getOrDefault("sourceNo", "").toString();
					e.put("queryId",codeToId.get(sourceCode));
				});
			}

			data.forEach(e->{
				e.put("thisSourceType",ConstantForMES.SCJH);
				e.put("thisSourceTypeName","生产计划");
			});
			if (isDialogType){
				return this.processData(data,pageno,pagesize);
			}
//			Map<String, Object> result = Maps.newHashMapWithExpectedSize(4);
//			result.put("data", new DsResultResponse(pageno, pagesize, total, data));
//			result.put("aGroupNumberTotal", aGroupNumberTotal);
//			result.put("bGroupNumberTotal", bGroupNumberTotal);
//			result.put("cGroupNumberTotal", cGroupNumberTotal);
			results.put("data", new DsResultResponse(pageno, pagesize, total, data));
		}
		return R.ok(results);
	}

	private R processData(List<Map<String, Object>> data, int pageno, int pagesize) {
		Map<String,Object> results = Maps.newHashMap();
		Map<String, Object> sourceParam;
		BigDecimal bySource;
		BigDecimal inspectionCount;
		for (Map<String, Object> datum : data) {

			sourceParam = Maps.newHashMap();
			sourceParam.put("sourceId", datum.get("id"));
			sourceParam.put("sourceType", ConstantForMES.SCJH);

			// 生产入库引用
			// 若生产计划为必检
			boolean isCheck = Integer.parseInt(datum.getOrDefault("isCheck", 0).toString()) == 1;
			bySource = stockInItemService.getCountBySource(sourceParam);
			BigDecimal countByOutSource = bySource == null ? BigDecimal.ZERO : bySource;
			if (isCheck) {
				sourceParam.put("inspectionType", ConstantForMES.CPJY);
				inspectionCount = materialInspectionService.getCountBySource(sourceParam);
				BigDecimal maxCount = inspectionCount == null ? BigDecimal.ZERO : inspectionCount;
				BigDecimal quoteCount = maxCount.subtract(countByOutSource);
				if (quoteCount.compareTo(BigDecimal.ZERO) <= 0) {
					datum.put("checkQuoteCount", quoteCount);
					datum.put("quoteCount", 0);
				} else {
					datum.put("quoteCount", quoteCount);
				}
			} else {
				BigDecimal maxCount = TypeUtils.castToBigDecimal(datum.get("completionMax"));
				// 若未设置最大限度 则代表无限制
				if (maxCount != null && maxCount.compareTo(BigDecimal.ZERO) > 0) {
					BigDecimal planCount = TypeUtils.castToBigDecimal(datum.get("planCount"));
					// 若计划数量还大余最大限度则取计划数量
					if (planCount.compareTo(maxCount) > 0) {
						maxCount = planCount;
					}
					BigDecimal quoteCount = maxCount.subtract(countByOutSource);
					if (quoteCount.compareTo(BigDecimal.ZERO) <= 0) {
						datum.put("quoteCount", 0);
					} else {
						datum.put("quoteCount", quoteCount);
					}
				}

			}

		}
		data.removeIf(e -> {
			Object quoteCount = e.get("quoteCount");
			return quoteCount != null && TypeUtils.castToBigDecimal(quoteCount).compareTo(BigDecimal.ZERO) == 0;
		});
		int total = data.size();
		if (data.size() > 0) {
			List<Map<String, Object>> quoteList = PageUtils.startPage(data, pageno, pagesize);
			results.put("data", new DsResultResponse(pageno,pagesize,total,quoteList));
		}
		return R.ok(results);
	}


	/**
	 * 获取生产计划的变更记录
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@EvApiByToken(value = "/apis/productionPlan/alterationList", method = RequestMethod.POST, apiTitle = "变更记录列表")
	@ApiOperation("获取变更记录列表")
	public R alterationList(
			@ApiParam(value = "当前第几页", required = true) @RequestParam(value = "pageno", defaultValue = "1") int pageno,
			@ApiParam(value = "一页多少条", required = true) @RequestParam(value = "pagesize", defaultValue = "20") int pagesize,
			@ApiParam(value = "生产计划ID") @RequestParam(value = "productionPlanId", defaultValue = "", required = false) Long productionPlanId,
			@ApiParam(value = "生产计划单号") @RequestParam(value = "planNo", defaultValue = "", required = false) String planNo,
			@ApiParam(value = "开始时间") @RequestParam(value = "startTime", defaultValue = "", required = false) String startTime,
			@ApiParam(value = "结束时间") @RequestParam(value = "endTime", defaultValue = "", required = false) String endTime,
			@ApiParam(value = "变更人ID") @RequestParam(value = "updateUser", defaultValue = "", required = false) Long updateUser,
			@ApiParam(value = "变更人姓名") @RequestParam(value = "updateUserName", defaultValue = "", required = false) String updateUserName
	) {
		// 查询列表数据
		Map<String, Object> params = Maps.newHashMapWithExpectedSize(8);

		params.put("startTime", startTime);
		params.put("endTime", endTime);
		params.put("productionPlanId", productionPlanId);
		params.put("createBy", updateUser);
		params.put("updateUserName", updateUserName);
		params.put("planNo", planNo);

		params.put("offset", (pageno - 1) * pagesize);
		params.put("limit", pagesize);
		Map<String, Object> results = Maps.newHashMapWithExpectedSize(1);
		List<Map<String, Object>> data = productionPlanAlterationService.listForMap(params);
		int total = productionPlanAlterationService.countForMap(params);
		if (data.size() > 0) {
			DsResultResponse dsRet = new DsResultResponse();
			dsRet.setDatas(data);
			dsRet.setPageno(pageno);
			dsRet.setPagesize(pagesize);
			dsRet.setTotalRows(total);
			dsRet.setTotalPages((total + pagesize - 1) / pagesize);
			results.put("data", dsRet);
		}
		return R.ok(results);
	}

	/**
	 * 保存生产计划
	 *
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/save", method = RequestMethod.POST, apiTitle = "保存生产计划信息")
	@ApiOperation("保存生产计划信息")
	public R save(ProductionPlanDO planDO) {
		if (productionPlanService.add(planDO) > 0) {
			Map<String, Object> result = Maps.newHashMapWithExpectedSize(1);
			result.put("id", planDO.getId());
			return R.ok(result);
		}
		return R.error();
	}

	/**
	 * 查看生产计划详情
	 *
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@EvApiByToken(value = "/apis/productionPlan/detail", method = RequestMethod.POST, apiTitle = "查看生产计划信息")
	@ApiOperation("查看生产计划信息")
	public R detail(
			@ApiParam(value = "生产计划Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		return R.ok(productionPlanService.getDetailInfo(id));
	}

	/**
	 * 修改生产计划
	 * @see  #alterationPlan(ProductionPlanDO) 变更生产计划
	 *
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/update", method = RequestMethod.POST, apiTitle = "修改生产计划")
	@ApiOperation("修改生产计划")
	public R update(ProductionPlanDO planDO) {
		ProductionPlanDO productionPlanDO = productionPlanService.get(planDO.getId());
		if (Objects.equals(ConstantForMES.CLOSE_CASE, productionPlanDO.getStatus())) {
			return R.error(messageSourceHandler.getMessage("receipt.closeCase.update.disabled",null));
		}
		if (!Objects.equals(ConstantForMES.PLAN, productionPlanDO.getStatus())) {
			return R.error(messageSourceHandler.getMessage("receipt.plan.alteration",null));
		}
		if (productionPlanService.edit(planDO) > 0) {
			return R.ok();
		}
		return R.error();
	}

	/**
	 * 下达生产计划
	 * 1、下达时检查是否有BOM存在，如果没有弹窗提示，如果有BOM，则调用BOM生成生产投料单，生产投料单上计划投料数量计算公式：生产计划单上的计划生产数量*BOM子项的标准用量/(1-损耗率)。
	 * 2、检查生产类型是否为工序跟踪，如果选择是，则工艺路线不能为空，如果为空则提示不能下达。如果有工艺路线，则根据配置的工艺路线自动生成对应的工序计划单。
	 * 3、将生产计划单状态更改为已下达
	 *
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/issuedPlan", method = RequestMethod.POST, apiTitle = "下达生产计划")
	@ApiOperation("下达生产计划")
	public R issuedPlan(
			@ApiParam(value = "生产计划Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		return productionPlanService.issuedPlan(id);
	}

	/**
	 * 批量下达生产计划
	 * 1、下达时检查是否有BOM存在，如果没有弹窗提示，如果有BOM，则调用BOM生成生产投料单，生产投料单上计划投料数量计算公式：生产计划单上的计划生产数量*BOM子项的标准用量/(1-损耗率)。
	 * 2、检查生产类型是否为工序跟踪，如果选择是，则工艺路线不能为空，如果为空则提示不能下达。如果有工艺路线，则根据配置的工艺路线自动生成对应的工序计划单。
	 * 3、将生产计划单状态更改为已下达
	 *
	 * @date 2020-10-13
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/batchIssuedPlans", method = RequestMethod.POST, apiTitle = "下达生产计划")
	@ApiOperation("下达生产计划")
	public R issuedPlan(
			@ApiParam(value = "生产计划主键数组", required = true, example = "1,2,3,4") @RequestParam(value = "ids", defaultValue = "") Long[] ids) {
		for (Long id : ids) {
			R r = productionPlanService.issuedPlan(id);
			if (Integer.parseInt(r.get("code").toString()) == 500) {
				ProductionPlanDO productionPlanDO = productionPlanService.get(id);
				String[]args = {productionPlanDO.getPlanNo()};
				return R.error(messageSourceHandler.getMessage("plan.issued.error",args));
			}
		}
		return R.ok();
	}

	/**
	 * 反下达生产计划
	 * 1、检查是否有对应的生产投料单和工序计划单存在，对应的生产投料单和工序计划单是否审核或下达，如果已审核或下达则生产计划单不能反下达；
	 * 2、对应的生产投料单和工序计划单存在，且为未审核和未下达状态则删除对应的生产投料单和工序计划单；
	 * 3、将单据状态修改为未下达
	 *
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/reverseIssuedPlan", method = RequestMethod.POST, apiTitle = "反下达生产计划")
	@ApiOperation("反下达生产计划")
	public R reverseIssuedPlan(
			@ApiParam(value = "生产计划Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		return productionPlanService.reverseIssuedPlan(id);
	}

	/**
	 * 挂起生产计划
	 * 1.下达状态的单据才能挂起
	 * 2.若有工序计划单并且是下达状态将工序计划单的状态修改为挂起
	 * 3.将工序计划单的下属工单全部修改为挂起状态
	 * 4.将生产计划修改为挂起状态
	 *
	 * @date 2019-11-29
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/putUpPlan", method = RequestMethod.POST, apiTitle = "挂起生产计划")
	@ApiOperation("挂起生产计划")
	public R putUpPlan(
			@ApiParam(value = "生产计划Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		return productionPlanService.putUpPlan(id);
	}

	/**
	 * 反挂起生产计划
	 * 1、检查对应的工序计划单状态，如果是挂起状态则修改为下达；
	 * 2、检查对应的生产工单状态，如果是挂起状态则修改为开工； XXX（未修改为开工，只将派工单修改为派工状态）
	 * 3、生产计划单状态修改为下达
	 *
	 * @date 2019-11-28
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/reversePutUpPlan", method = RequestMethod.POST, apiTitle = "反挂起生产计划")
	@ApiOperation("反挂起生产计划")
	public R reversePutUpPlan(
			@ApiParam(value = "生产计划Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		return productionPlanService.reversePutUpPlan(id);
	}

	/**
	 * 结案生产计划
	 * 1、检查单据是否为计划、结案状态，如果是计划状态则无须变更可直接修改，如果是结案状态则不能变更。
	 * 2、如果是下达状态，对应的工序计划不允许有派工存在。如果没有派工记录存在，调出生产计划单编辑界面，同时开放计划生产数量、计划开工时间和计划完工时间允许修改。
	 * 3、如果是调整工艺路线，则无须变更生产计划，变更对应的工序计划单中的工序配置即可。
	 * 4、变更保存后调整对应的工序计划单中的计划生产数量、计划开工日期和计划完工日期。
	 * 5、生成变更记录
	 *
	 * @date 2019-11-28
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/closeCase", method = RequestMethod.POST, apiTitle = "结案生产计划")
	@ApiOperation("结案生产计划")
	public R closeCase(
			@ApiParam(value = "生产计划Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		return productionPlanService.closeCasePlan(id);
	}

	/**
	 * 反结案生产计划
	 * 1.若工序计划单已结案不能反结案
	 * 2.将结案的生产投料单改回已审核状态
	 * 3.将生产计划单修改为下达状态
	 *
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/reverseCloseCase", method = RequestMethod.POST, apiTitle = "反结案生产计划")
	@ApiOperation("反结案生产计划")
	public R reverseCloseCase(
			@ApiParam(value = "生产计划Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		return productionPlanService.reverseCloseCasePlan(id);
	}

	/**
	 * 变更生产计划
	 * 1、检查单据是否为计划、结案状态，如果是计划状态则无须变更可直接修改，如果是结案状态则不能变更。
	 * 2、如果是下达状态，对应的工序计划不允许有派工存在。如果没有派工记录存在，调出生产计划单编辑界面，同时开放计划生产数量、计划开工时间和计划完工时间允许修改。
	 * 3、如果是调整工艺路线，则无须变更生产计划，变更对应的工序计划单中的工序配置即可。
	 * 4、变更保存后调整对应的工序计划单中的计划生产数量、计划开工日期和计划完工日期。
	 * 5、生成变更记录
	 *
	 * @date 2019-11-28
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/alterationPlan", method = RequestMethod.POST, apiTitle = "变更生产计划")
	@ApiOperation("变更生产计划")
	public R alterationPlan(ProductionPlanDO planDO) {
		return productionPlanService.alterationPlan(planDO);
	}

	/**
	 * 变更生产计划(获取是否存在派工单)
	 *
	 * @date 2019-12-12
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/isAlterationPlan", method = RequestMethod.POST, apiTitle = "变更生产计划(获取是否存在派工单)")
	@ApiOperation("变更生产计划(获取是否存在派工单)")
	public R isAlterationPlan(@ApiParam(value = "生产计划主键", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		List<WorkingProcedurePlanDO> planList = productionPlanService.getWorkingProcedurePlanList(id, Maps.newHashMap());
		if (planList.size()>0){
			Map<String,Object> params;
			for (WorkingProcedurePlanDO workingProcedurePlanDO: planList) {
				params = Maps.newHashMap();
				params.put("planId", workingProcedurePlanDO.getId());
				int count = workingProcedurePlanService.dispatchItemCount(params);
				if (count>0){
					return R.error(messageSourceHandler.getMessage("receipt.plan.isAlterationPlan",null));
				}
			}
		}
		return  R.ok();
	}

	/**
	 * 删除单个生产计划单
	 * 删除：删除当前选中生产计划，已经下达或被关联引用提示不能删除
	 *
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/remove", method = RequestMethod.POST, apiTitle = "删除生产计划信息")
	@ApiOperation("删除生产计划信息")
	public R remove(
			@ApiParam(value = "生产计划主键", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
		return productionPlanService.delete(id);
	}

	/**
	 * 批量删除生产计划单
	 * 删除：删除当前选中生产计划，已经下达或被关联引用提示不能删除
	 *
	 * @date 2019-11-27
	 * @author gumingjie
	 */
	@Transactional(rollbackFor = Exception.class)
	@EvApiByToken(value = "/apis/productionPlan/batchRemove", method = RequestMethod.POST, apiTitle = "批量删除生产计划信息")
	@ApiOperation("批量删除生产计划信息")
	public R remove(
			@ApiParam(value = "生产计划主键数组", required = true, example = "1,2,3,4") @RequestParam(value = "ids", defaultValue = "") Long[] ids) {
		return productionPlanService.batchDelete(ids);
	}

	/**
	 * 跟踪工序计划
	 * 1、根据生产计划关联的下游单据列表显示工序计划、工序派工和报工的跟踪信息，显示方式为向下连查。
	 *
	 * @date 2019-11-30
	 * @author gumingjie
	 */
	@EvApiByToken(value = "/apis/productionPlan/followPlan", method = RequestMethod.POST, apiTitle = "跟踪")
	@ApiOperation("跟踪")
	public R followPlan(
			@ApiParam(value = "生产计划Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id){
		return productionPlanService.followPlan(id);
	}

	/**
	 *
	 * 爱塞璐根据选择的生产任务单的主键id获取bom数据
	 *
	 * @date 2019-11-30
	 * @author gumingjie
	 */
	@EvApiByToken(value = "/apis/productionPlan/aslGetBomByPlanId", method = RequestMethod.POST, apiTitle = "爱塞璐根据选择的生产任务单的主键id获取bom数据")
	@ApiOperation("爱塞璐根据选择的生产任务单的主键id获取bom数据")
	public R aslGetBomByPlanId(@ApiParam(value = "生产任务单id", required = true) @RequestParam(value = "id", defaultValue = "") Long id){

		ProductionPlanDO productionPlanDO = productionPlanService.get(id);
		//获取bom信息
		BomDO bomDO = bomService.get(productionPlanDO.getBomId());

		MaterielDO materiel = materielService.get(productionPlanDO.getMaterielId());

		Map<String, Object> map = new HashMap<>();

		//容量
		map.put("productCapacity",materiel.getVolume());
		//重量
		map.put("weight",materiel.getNetWeight());
		//品名
		map.put("materielName",materiel.getName());
		//品名Id
		map.put("materielId",materiel.getId());

		//客户名
		map.put("clientName",productionPlanDO.getClientName());
		//客户Id
		map.put("clientId",productionPlanDO.getClientId());

		map.put("aGroupNumber",productionPlanDO.getAGroupNumber());
		map.put("bGroupNumber",productionPlanDO.getBGroupNumber());
		map.put("cGroupNumber",productionPlanDO.getCGroupNumber());

		Map<String, Object> params = Maps.newHashMapWithExpectedSize(2);

		params.put("bomId", bomDO.getId());

		// 一级
		List<BomDetailDO> bomDetailDOSOne = bomDetailService.list(params);
		//判断一级原料是否自制件，是的话，就根据物料编号去bom单中查询指定的一级原料的子bom
		List<Long> parentMaterielIds = bomDetailDOSOne.stream().filter(e->AslConstant.TWO.equals(e.getMaterielType())).map(BomDetailDO::getMaterielId).collect(Collectors.toList());
		//所有物料的ids
		List<Long> materielIds = bomDetailDOSOne.stream().filter(e->!AslConstant.TWO.equals(e.getMaterielType())).map(BomDetailDO::getMaterielId).collect(Collectors.toList());

		//二级bomId
		params.remove("bomId");
		//二级bom
		List<BomDO> twoBomDOS = null;
		//二级bom子原料
		List<BomDetailDO> bomDetailDOSTwo = null;
		if (!CollectionUtils.isEmpty(parentMaterielIds)) {
			params.put("materielIds", parentMaterielIds);
			//二级bom
			twoBomDOS = bomService.list(params);
			List<Long> twoBomIds = twoBomDOS.stream().map(BomDO::getId)
					.collect(Collectors.toList());
			params.remove("materielIds");
			params.put("bomIds", twoBomIds);
			//二级bom子原料
			bomDetailDOSTwo = bomDetailService.list(params);
			materielIds.addAll(bomDetailDOSTwo.stream().map(BomDetailDO::getMaterielId).collect(Collectors.toList()));
		}

		params.remove("bomIds");
		params.put("ids", materielIds);
		Map<String, Object> bomOfMeteiielIds = Maps.newHashMapWithExpectedSize(2);
		bomOfMeteiielIds.put("ids", materielIds);
		List<MaterielDO> materielDOList = materielService.listTwo(params);

		List<Map<String, Object>> mapList = new ArrayList<>();

		//求原料的总用量
		BigDecimal totalAmount = BigDecimal.ZERO;
		List<BomDetailDO> bomDetailDOS = new ArrayList<>();
		bomDetailDOS.addAll(bomDetailDOSOne.stream().filter(e -> !AslConstant.TWO.equals(e.getMaterielType()))
				.collect(Collectors.toList()));
		if (!CollectionUtils.isEmpty(bomDetailDOSTwo)){
			bomDetailDOS.addAll(bomDetailDOSTwo);
		}

		for (BomDetailDO detailDO : bomDetailDOS) {
			totalAmount = totalAmount.add(
					detailDO.getStandardCount() != null ? detailDO.getStandardCount() : BigDecimal.ZERO)
					.setScale(2, BigDecimal.ROUND_HALF_UP);
		}

		BigDecimal proportion = BigDecimal.ZERO;

		for (BomDetailDO detailDO : bomDetailDOSOne) {
			Map<String, Object> objectMap = new HashMap<>();
			//无下级子物料时
			if (!AslConstant.TWO.equals(detailDO.getMaterielType())) {
				for (MaterielDO materielDO : materielDOList) {
					if (detailDO.getMaterielId().equals(materielDO.getId())) {
						//层次
						objectMap.put("level", materielDO.getName());
						//原料编码
						objectMap.put("rawMaterialCode", materielDO.getSerialNo());
						//原料名称
						objectMap.put("rawMaterialName", materielDO.getName());
						//规格型号
						objectMap.put("specification", materielDO.getSpecification());
						//计量单位
						objectMap.put("unitUom", materielDO.getUnitUom());
						//计量单位名称
						objectMap.put("unitUomName", materielDO.getUnitUomName());
						//用量
						objectMap.put("standardCount", detailDO.getStandardCount());
						proportion = detailDO.getStandardCount()
								.divide(totalAmount, BigDecimal.ROUND_HALF_UP)
								.multiply(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP);
						//比例
						objectMap.put("proportion", proportion);
						objectMap.put("cbcount", AslConstant.ONE);
						objectMap.put("cbaa", AslConstant.ZERO);
						mapList.add(objectMap);
					}

				}
			}
			if (AslConstant.TWO.equals(detailDO.getMaterielType())) {
				if (!CollectionUtils.isEmpty(twoBomDOS)) {
					for (BomDO bomDO1 : twoBomDOS) {
						if (detailDO.getMaterielId().equals(bomDO1.getMaterielId())) {
							int cbcount = AslConstant.ZERO;
							if (!CollectionUtils.isEmpty(bomDetailDOSTwo)) {
								for (BomDetailDO detailDO1 : bomDetailDOSTwo) {

									if (bomDO1.getId().equals(detailDO1.getBomId())) {
										for (MaterielDO materielDO : materielDOList) {
											if (bomDO1.getMaterielId().equals(materielDO.getId())) {
												objectMap.put("level", materielDO.getName());
											}
											if (detailDO1.getMaterielId()
													.equals(materielDO.getId())) {
												//原料编码
												objectMap.put("rawMaterialCode",
														materielDO.getSerialNo());
												//原料名称
												objectMap.put("rawMaterialName",
														materielDO.getName());
												//规格型号
												objectMap.put("specification",
														materielDO.getSpecification());
												//计量单位
												objectMap.put("unitUom", materielDO.getUnitUom());
												//计量单位名称
												objectMap.put("unitUomName", materielDO.getUnitUomName());
											}
										}
										//比例
										cbcount = cbcount + 1;
										objectMap.put("cbaa", cbcount);
										//用量
										objectMap.put("standardCount",
												detailDO1.getStandardCount());
										proportion = detailDO1.getStandardCount()
												.divide(totalAmount, BigDecimal.ROUND_HALF_UP)
												.multiply(new BigDecimal("100"))
												.setScale(2, BigDecimal.ROUND_HALF_UP);

										objectMap.put("proportion", proportion);
									}
								}
								objectMap.put("cbcount", cbcount);
								mapList.add(objectMap);
							}

						}
					}
				}

			}

		}

		Map<String,Object> map1 = new HashMap<>();
		map1.put("bomList",mapList);
		map1.put("ylcount",mapList.size());
		map.put("bom",map1);
		map.put("bomNo",bomDO.getSerialno());

		return R.ok(map);
	}
	/**
	 *
	 * 爱塞璐根据选择的生产任务单的主键id获取bom数据
	 *
	 * @date 2019-11-30
	 * @author gumingjie
	 */
	@EvApiByToken(value = "/apis/productionPlan/aslGetBomByPlanId2", method = RequestMethod.POST, apiTitle = "爱塞璐根据选择的生产任务单的主键id获取bom数据")
	@ApiOperation("爱塞璐根据选择的生产任务单的主键id获取bom数据")
	public R aslGetBomByPlanId2(@ApiParam(value = "生产任务单id", required = true) @RequestParam(value = "id", defaultValue = "") Long id){

		ProductionPlanDO productionPlanDO = productionPlanService.get(id);
		//获取bom信息
		BomDO bomDO = bomService.get(productionPlanDO.getBomId());

		MaterielDO materiel = materielService.get(productionPlanDO.getMaterielId());

		Map<String, Object> map = new HashMap<>();

		//容量
		map.put("productCapacity",materiel.getVolume());
		//重量
		map.put("weight",materiel.getNetWeight());
		//品名
		map.put("materielName",materiel.getName());
		//品名Id
		map.put("materielId",materiel.getId());

		//客户名
		map.put("clientName",productionPlanDO.getClientName());
		//客户Id
		map.put("clientId",productionPlanDO.getClientId());

		map.put("aGroupNumber",productionPlanDO.getAGroupNumber());
		map.put("bGroupNumber",productionPlanDO.getBGroupNumber());
		map.put("cGroupNumber",productionPlanDO.getCGroupNumber());

		Map<String, Object> params = Maps.newHashMapWithExpectedSize(2);

		params.put("bomId", bomDO.getId());

		// 一级
		List<BomDetailDO> bomDetailDOSOne = bomDetailService.list(params);
		//判断一级原料是否自制件，是的话，就根据物料编号去bom单中查询指定的一级原料的子bom
		List<Long> parentMaterielIds = bomDetailDOSOne.stream().filter(e->AslConstant.TWO.equals(e.getMaterielType())).map(BomDetailDO::getMaterielId).collect(Collectors.toList());
		//所有物料的ids
		List<Long> materielIds = bomDetailDOSOne.stream().filter(e->!AslConstant.TWO.equals(e.getMaterielType())).map(BomDetailDO::getMaterielId).collect(Collectors.toList());

		//二级bomId
		params.remove("bomId");
		//二级bom
		List<BomDO> twoBomDOS = null;
		//二级bom子原料
		List<BomDetailDO> bomDetailDOSTwo = null;
		if (!CollectionUtils.isEmpty(parentMaterielIds)) {
			params.put("materielIds", parentMaterielIds);
			//二级bom
			twoBomDOS = bomService.list(params);
			List<Long> twoBomIds = twoBomDOS.stream().map(BomDO::getId)
					.collect(Collectors.toList());
			params.remove("materielIds");
			params.put("bomIds", twoBomIds);
			//二级bom子原料
			bomDetailDOSTwo = bomDetailService.list(params);
			materielIds.addAll(bomDetailDOSTwo.stream().map(BomDetailDO::getMaterielId).collect(Collectors.toList()));
		}

		params.remove("bomIds");
		params.put("ids", materielIds);
		List<MaterielDO> materielDOList = materielService.listTwo(params);

		List<Map<String, Object>> mapList = new ArrayList<>();

		//求原料的总用量
		BigDecimal totalAmount = BigDecimal.ZERO;
		List<BomDetailDO> bomDetailDOS = new ArrayList<>();
		bomDetailDOS.addAll(bomDetailDOSOne.stream().filter(e -> !AslConstant.TWO.equals(e.getMaterielType()))
				.collect(Collectors.toList()));
		if (!CollectionUtils.isEmpty(bomDetailDOSTwo)){
			bomDetailDOS.addAll(bomDetailDOSTwo);
		}

		for (BomDetailDO detailDO : bomDetailDOS) {
			totalAmount = totalAmount.add(
					detailDO.getStandardCount() != null ? detailDO.getStandardCount() : BigDecimal.ZERO)
					.setScale(2, BigDecimal.ROUND_HALF_UP);
		}

		BigDecimal proportion = BigDecimal.ZERO;

//		for (BomDetailDO detailDO : bomDetailDOSOne) {
//			Map<String, Object> objectMap = new HashMap<>();
//			//无下级子物料时
//			if (!AslConstant.TWO.equals(detailDO.getMaterielType())) {
//				for (MaterielDO materielDO : materielDOList) {
//					if (detailDO.getMaterielId().equals(materielDO.getId())) {
//						//层次
//						objectMap.put("level", materielDO.getName());
//						//原料编码
//						objectMap.put("rawMaterialCode", materielDO.getSerialNo());
//						//原料名称
//						objectMap.put("rawMaterialName", materielDO.getName());
//						//规格型号
//						objectMap.put("specification", materielDO.getSpecification());
//						//计量单位
//						objectMap.put("unitUom", materielDO.getUnitUom());
//						//用量
//						objectMap.put("standardCount", detailDO.getStandardCount());
//						proportion = detailDO.getStandardCount()
//								.divide(totalAmount, BigDecimal.ROUND_HALF_UP)
//								.multiply(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP);
//						//比例
//						objectMap.put("proportion", proportion);
//						objectMap.put("cbcount", AslConstant.ONE);
//						objectMap.put("cbaa", AslConstant.ZERO);
//						mapList.add(objectMap);
//					}
//
//				}
//			}
//			if (AslConstant.TWO.equals(detailDO.getMaterielType())) {
//				if (!CollectionUtils.isEmpty(twoBomDOS)) {
//					for (BomDO bomDO1 : twoBomDOS) {
//						if (detailDO.getMaterielId().equals(bomDO1.getMaterielId())) {
//							int cbcount = AslConstant.ZERO;
//							if (!CollectionUtils.isEmpty(bomDetailDOSTwo)) {
//								for (BomDetailDO detailDO1 : bomDetailDOSTwo) {
//
//									if (bomDO1.getId().equals(detailDO1.getBomId())) {
//										for (MaterielDO materielDO : materielDOList) {
//											if (bomDO1.getMaterielId().equals(materielDO.getId())) {
//												objectMap.put("level", materielDO.getName());
//											}
//											if (detailDO1.getMaterielId()
//													.equals(materielDO.getId())) {
//												//原料编码
//												objectMap.put("rawMaterialCode",
//														materielDO.getSerialNo());
//												//原料名称
//												objectMap.put("rawMaterialName",
//														materielDO.getName());
//												//规格型号
//												objectMap.put("specification",
//														materielDO.getSpecification());
//												//计量单位
//												objectMap.put("unitUom", materielDO.getUnitUom());
//											}
//										}
//										//比例
//										cbcount = cbcount + 1;
//										objectMap.put("cbaa", cbcount);
//										//用量
//										objectMap.put("standardCount",
//												detailDO1.getStandardCount());
//										proportion = detailDO1.getStandardCount()
//												.divide(totalAmount, BigDecimal.ROUND_HALF_UP)
//												.multiply(new BigDecimal("100"))
//												.setScale(2, BigDecimal.ROUND_HALF_UP);
//
//										objectMap.put("proportion", proportion);
//									}
//								}
//								objectMap.put("cbcount", cbcount);
//								mapList.add(objectMap);
//							}
//
//						}
//					}
//				}
//
//			}
//
//		}
		Map<Long,String> materialNameAndId = materielDOList.stream().collect(Collectors.toMap(MaterielDO::getId, MaterielDO::getName, (v1, v2) -> v1));
		//一层
		if (!ObjectUtils.isEmpty(bomDO)) {
			Map<String, Object> objectMap = new HashMap<>();
			objectMap.put("level", "外层");
			objectMap.put("cbcount1", 0);
			//原料名称
			objectMap.put("name1", materiel.getName());
			objectMap.put("proportion1", 0.00);
			mapList.add(objectMap);
		}
		//二层
//        bomDetailDOSOne.add(bomDetailDOSOne.get(1));
//        bomDetailDOSOne.add(bomDetailDOSOne.get(1));
		if (!ObjectUtils.isEmpty(bomDetailDOSOne)){
			int num = 1;
			Map<String, Object> objectMap = new HashMap<>();
			objectMap.put("level", "中层");
			for (int i = 0; i < bomDetailDOSOne.size(); i++) {
				for (MaterielDO materielDO : materielDOList) {
					if (bomDetailDOSOne.get(i).getMaterielId().equals(materielDO.getId())) {
						String name = "name";
						String cbcount = "cbcount";
						//原料名称
						if (AslConstant.TWO.equals(bomDetailDOSOne.get(i).getMaterielType())){
							objectMap.put(cbcount + num, 0);
						}else {
							objectMap.put(cbcount + num, 1);
						}
						objectMap.put(name + num, materielDO.getName());
						proportion = bomDetailDOSOne.get(i).getStandardCount()
								.divide(totalAmount, BigDecimal.ROUND_HALF_UP)
								.multiply(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP);
						//比例
						objectMap.put("proportion" + num, proportion);
						num = num+1;
					}
				}
			}
			mapList.add(objectMap);
		}
//        twoBomDOS = new ArrayList<BomDO>();
//        BomDO bomDO1 = new BomDO();
//        BomDO bomDO2 = new BomDO();
//        BomDO bomDO3 = new BomDO();
//        bomDO1.setMaterielId(270l);
//        bomDO2.setMaterielId(270l);
//        bomDO3.setMaterielId(270l);
//        twoBomDOS.add(bomDO1);
//        twoBomDOS.add(bomDO2);
//        twoBomDOS.add(bomDO3);
		//三层
		if (!CollectionUtils.isEmpty(twoBomDOS)) {
			Map<Long,BigDecimal> bomDetailDOSTwoAndCount = bomDetailDOSTwo.stream().collect(Collectors.toMap(BomDetailDO::getBomId, BomDetailDO::getStandardCount, (v1, v2) -> v1));
			int num = 1;
			Map<String, Object> threeMap = new HashMap<>();
			threeMap.put("level", "内层");
			for (int i = 0; i < twoBomDOS.size(); i++) {
				BomDO bomOne = twoBomDOS.get(i);
				threeMap.put("name" + num, materialNameAndId.get(bomOne.getMaterielId()));
				threeMap.put("cbcount" + num, 0);
				proportion = bomDetailDOSTwoAndCount.get(bomOne.getId())
						.divide(totalAmount, BigDecimal.ROUND_HALF_UP)
						.multiply(new BigDecimal("100"))
						.setScale(2, BigDecimal.ROUND_HALF_UP);

				threeMap.put("proportion" + num, proportion);
				num = num+1;
			}
			mapList.add(threeMap);
		}

		Map<String,Object> map1 = new HashMap<>();
		map1.put("bomList",mapList);
		map1.put("ylcount",mapList.size());
		map.put("bom",map1);
		map.put("bomNo",bomDO.getSerialno());

		return R.ok(map);
	}
	/**
	 *
	 * 爱塞璐根据选择的生产任务单的主键id获取bom数据
	 *
	 * @date 2019-11-30
	 * @author gumingjie
	 */
	@EvApiByToken(value = "/apis/productionPlan/aslGetBomByPlanId3", method = RequestMethod.POST, apiTitle = "爱塞璐根据选择的生产任务单的主键id获取bom数据")
	@ApiOperation("爱塞璐根据选择的生产任务单的主键id获取bom数据")
	public R aslGetBomByPlanId3(@ApiParam(value = "生产任务单id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {

		Map<String, Object> map = new HashMap<>();
		Map<String, Object> rawMaterialRatio = new HashMap<>();
		ProductionPlanDO productionPlanDO = productionPlanService.get(id);
		//获取bom信息
		Map<String, Object> map2 = new HashMap<>();
		ArrayList<Long> ids = new ArrayList<>();
		ids.add(productionPlanDO.getMaterielId());
		map2.put("bomIds", ids);
		//产品的子物料
		List<BomDO2> bomDO2 = bomService.getDO2(map2);
		if (ObjectUtils.isEmpty(bomDO2)) {
			return R.ok(map);
		}
		List<Long> childIds = bomDO2.stream().map(BomDO2::getChildMaterielId).collect(Collectors.toList());
		map2.put("bomIds", childIds);
		//子物料的子物料
		List<BomDO2> bomDO3 = bomService.getDO2(map2);
		if (ObjectUtils.isEmpty(bomDO2) || bomDO2.size() <= 0) {
			return R.ok(map);
		}
		Map<Long, List<BomDO2>> collect = bomDO3.stream().collect(Collectors.groupingBy(BomDO2::getMaterielId));
		List<BomDO2> list = new ArrayList<>();
		int j = 0;
		for (int i = 0; i < 3; i++) {
			if (i < bomDO2.size()) {
				rawMaterialRatio.put("name" + ++j, bomDO2.get(i).getChildMaterielName());
				list = collect.get(bomDO2.get(i).getChildMaterielId());
				if (ObjectUtils.isEmpty(list) || list.size() <= 0) {
					rawMaterialRatio.put("name" + ++j, "");
					rawMaterialRatio.put("name" + ++j, "");
					rawMaterialRatio.put("name" + ++j, "");
				} else {
					for (int n = 0; n < 3; n++) {
						if (n < list.size()) {
							rawMaterialRatio.put("name" + ++j, list.get(n).getChildMaterielName());
						} else {
							rawMaterialRatio.put("name" + ++j, "");
						}
					}
				}
			} else {
				rawMaterialRatio.put("name" + ++j, "");
				rawMaterialRatio.put("name" + ++j, "");
				rawMaterialRatio.put("name" + ++j, "");
				rawMaterialRatio.put("name" + ++j, "");
			}
		}

		rawMaterialRatio.put("proportion1", "");
		rawMaterialRatio.put("proportion2", "");
		rawMaterialRatio.put("proportion3", "");
		rawMaterialRatio.put("proportion4", "");
		rawMaterialRatio.put("proportion5", "");
		rawMaterialRatio.put("proportion6", "");
		rawMaterialRatio.put("proportion7", "");
		rawMaterialRatio.put("proportion8", "");
		rawMaterialRatio.put("proportion9", "");
		rawMaterialRatio.put("proportion10", "");
		rawMaterialRatio.put("proportion11", "");
		rawMaterialRatio.put("proportion12", "");
		map.put("data", rawMaterialRatio);
		return R.ok(map);
	}
}
